package com.jiazhong.example.project.bookstore.front.service.impl;

import com.jiazhong.example.project.bookstore.commons.bean.Book;
import com.jiazhong.example.project.bookstore.commons.bean.ShoppingCart;
import com.jiazhong.example.project.bookstore.commons.config.JwtConfig;
import com.jiazhong.example.project.bookstore.commons.handler.ShoppingCartChangeNumberException;
import com.jiazhong.example.project.bookstore.commons.mapper.BookMapper;
import com.jiazhong.example.project.bookstore.commons.mapper.ShoppingCartMapper;
import com.jiazhong.example.project.bookstore.commons.util.JsonResult;
import com.jiazhong.example.project.bookstore.commons.util.ResultTool;
import com.jiazhong.example.project.bookstore.front.service.BookService;
import com.jiazhong.example.project.bookstore.front.service.ShoppingCartService;
import io.jsonwebtoken.Claims;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.NumberFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Slf4j
@Service
public class ShoppingCartServiceImpl implements ShoppingCartService {
    @Resource
    private BookMapper bookMapper;

    private StringRedisTemplate stringRedisTemplate;
    private HashOperations<String, String, String> forHash;

    public static final String SHOPPING_CART_PREFIX = "shoppingCart:";

    public ShoppingCartServiceImpl(@Autowired StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.forHash = stringRedisTemplate.opsForHash();
    }

    @CacheEvict(cacheNames = "findCartByUserId", key = "#request.getHeader('token')")
    public JsonResult addCart(String bookId, HttpServletRequest request) {
        // 1. 获取到我的购物车
        String token = request.getHeader("token");
        Claims claims = JwtConfig.parseJWT(token);
        String userId = claims.get("id").toString();
        Map<String, String> carts = forHash.entries(SHOPPING_CART_PREFIX + userId);
        // 2.向购物车中添加商品
        if (carts == null || carts.isEmpty()) {
            // 2.1 第一次添加购物车
            forHash.put(SHOPPING_CART_PREFIX + userId, bookId, "1");
            return ResultTool.success("success");
        }
        // 2.2 我存在购物车，判断商品是否在购物车中存在
        boolean containsKey = carts.containsKey(bookId);
        if (containsKey) {
            // 2.3 如果存在，数量+1
            forHash.increment(SHOPPING_CART_PREFIX + userId, bookId, 1);
        } else {
            // 2.4 存放并覆盖原来的购物车
            carts.put(bookId, "1");
            forHash.put(SHOPPING_CART_PREFIX + userId, bookId, "1");
            // forHash.putAll(SHOPPING_CART_PREFIX + userId, carts);
        }
        return ResultTool.success("success");
    }

    @Cacheable(cacheNames = "findCartByUserId", key = "#request.getHeader('token')")
    public JsonResult findCartByUserId(HttpServletRequest request) {
        // 获取到我的购物车
        String token = request.getHeader("token");
        Claims claims = JwtConfig.parseJWT(token);
        String userId = claims.get("id").toString();
        Map<String, String> carts = forHash.entries(SHOPPING_CART_PREFIX + userId);
        // 查询数据库 获取到所有的详细信息
        Set<String> books = carts.keySet();
        List<Book> myCarts = bookMapper.findBookByBookId(books);
        for (Book book : myCarts) {
            // 计算折扣后的价格
            if (book.getDiscountRate() == null) {
                book.setDiscountPrice(book.getPrice());
            } else {
                double p = book.getDiscountRate() * book.getPrice();
                NumberFormat numberFormat = NumberFormat.getInstance();
                numberFormat.setMaximumFractionDigits(2);
                String format = numberFormat.format(p);
                book.setDiscountPrice(Double.parseDouble(format));
            }

            // 设置购物车的该本图书数量
            String number = carts.get(book.getId());
            book.setCartNum(Integer.parseInt(number));
        }
        return ResultTool.success(myCarts);
    }

    @CacheEvict(cacheNames = "findCartByUserId", key = "#request.getHeader('token')")
    public JsonResult updateCartNumberIncrement(String bookId, HttpServletRequest request) {
        // 获取到我的购物车
        String token = request.getHeader("token");
        Claims claims = JwtConfig.parseJWT(token);
        String userId = claims.get("id").toString();
        // 更新购物车，redis中userId对应的bookId自增1
        Long increment = forHash.increment(SHOPPING_CART_PREFIX + userId, bookId, 1);
        if (increment == 0) {
            throw new ShoppingCartChangeNumberException("更新购物车失败");
        }
        return ResultTool.success("success");
    }

    @CacheEvict(cacheNames = "findCartByUserId", key = "#request.getHeader('token')")
    public JsonResult updateCartNumberDecrement(String bookId, HttpServletRequest request) {
        // 获取到我的购物车
        String token = request.getHeader("token");
        Claims claims = JwtConfig.parseJWT(token);
        String userId = claims.get("id").toString();
        // 更新购物车，redis中userId对应的bookId自增1
        Long increment = forHash.increment(SHOPPING_CART_PREFIX + userId, bookId, -1);
        if (increment == 0) {
            throw new ShoppingCartChangeNumberException("更新购物车失败");
        }
        return ResultTool.success("success");
    }

    @CacheEvict(cacheNames = "findCartByUserId", key = "#request.getHeader('token')")
    public JsonResult updateCartNumber(String bookId, int number, HttpServletRequest request) {
        // 获取到我的购物车
        String token = request.getHeader("token");
        Claims claims = JwtConfig.parseJWT(token);
        String userId = claims.get("id").toString();
        // 更新购物车，redis中userId对应的bookId自增1
        forHash.put(SHOPPING_CART_PREFIX + userId, bookId, number + "");
        return ResultTool.success("success");
    }

    @CacheEvict(cacheNames = "findCartByUserId", key = "#request.getHeader('token')")
    public JsonResult removeCart(String bookId, HttpServletRequest request) {
        // 获取到我的购物车
        String token = request.getHeader("token");
        Claims claims = JwtConfig.parseJWT(token);
        String userId = claims.get("id").toString();
        forHash.delete(SHOPPING_CART_PREFIX + userId, bookId);
        return ResultTool.success("success");
    }

    @CacheEvict(cacheNames = "findCartByUserId", key = "#request.getHeader('token')")
    public JsonResult removeCartBatch(String[] bookIds, HttpServletRequest request) {
        // 获取到我的购物车
        String token = request.getHeader("token");
        Claims claims = JwtConfig.parseJWT(token);
        String userId = claims.get("id").toString();
        forHash.delete(SHOPPING_CART_PREFIX + userId, bookIds);

        return ResultTool.success("success");
    }

    @Resource
    private ShoppingCartMapper shoppingCartMapper;

    // 不是我调用，定时执行（在一个具体的时间下去执行这个方法）
    @Scheduled(cron = "0 44 14 * * *")
    @Transactional
    public void scheduledBackup() {
        // 1. 清空shopping_cart表
        shoppingCartMapper.clearTable();
        // 2. 将redis中的所有购物车数据备份（insert）到mysql
        Set<String> shoppingCartKeys = stringRedisTemplate.keys(SHOPPING_CART_PREFIX + "*");
        for (String shoppingCartKey : shoppingCartKeys) {
            String key = shoppingCartKey;
            String userId = key.replaceAll(SHOPPING_CART_PREFIX, "");
            Map<String, String> entries = forHash.entries(key);
            Set<String> bookIds = entries.keySet();
            for (String bookId : bookIds) {
                String number = forHash.get(key, bookId);
                ShoppingCart sc = new ShoppingCart();
                sc.setBookId(bookId);
                sc.setNumber(Integer.parseInt(number));
                sc.setUserId(userId);
                shoppingCartMapper.insert(sc);
            }
        }
        // insert into shopping_cart values(null,userid,bookid,number,0)
    }
}
